using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Newtonsoft.Json;

namespace touhou_bullet_rain;

public class LevelAction {

    public string a;
    public string[] p;
    public long ts = 0;

    [JsonIgnore] public string ActionName { get => a; set => a = value; }
    [JsonIgnore] public string[] ParamsList { get => p; set => p = value; }
    [JsonIgnore] public long TimeStamp { get => ts; set => ts = value; }

    /// <summary>
    /// 服务器传入报头和实际含义对应字典
    /// </summary>
    private Dictionary<string, string> actionDic = new Dictionary<string, string> {
        { "e", "echo" },
        { "sn", "server_name" },
        { "si", "server_info" },
        { "gs", "game_status" },
        { "b", "boardcast" },
        { "pla", "player_action" },
        { "pja", "projectile_action" },
        { "ya", "youkai_action" },
        { "ia", "item_action" },
        { "cp", "create_player" },
        { "cb", "create_bullet" },
        { "cy", "create_youkai" },
        { "ci", "create_item" },
        { "dp", "del_player" },
        { "db", "del_bullet" },
        { "dy", "del_youkai" },
        { "di", "del_item" },
        { "pb", "particle_burst" }
    };

    public LevelAction(string actionName, string[] paramsList) {
        ActionName = actionName;
        ParamsList = paramsList;
        DateTime utcNow = DateTime.UtcNow;
        DateTime unixStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        TimeSpan timeSpan = utcNow - unixStart;
        TimeStamp = (long)timeSpan.TotalMilliseconds;
    }

    /// <summary>
    /// 序列化信息
    /// </summary>
    public string SerializeAction() {
        string result = JsonConvert.SerializeObject(this);
        return result;
    }

    /// <summary>
    /// 将传入会话的信息进行处理
    /// </summary>
    public void HandleLevelAction(Level level) {
        try {
            string ActionName = actionDic[this.ActionName];
            if (ActionName == "echo") {
                if (GameManager.uuid == ParamsList[0]) {
                    level.mostRecentCallBackTime = TimeStamp;
                    DateTime utcNow = DateTime.UtcNow;
                    DateTime unixStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                    TimeSpan timeSpan = utcNow - unixStart;
                    level.receiveTimeSpan = (long)timeSpan.TotalMilliseconds;
                    level.latency = level.receiveTimeSpan - level.mostRecentInteractTime;
                }
            }
            else if (ActionName == "server_name") {
                level.serverName = ParamsList[0];
            }
            else if (ActionName == "server_info") {
                level.serverInfo = ParamsList;
            }
            else if (ActionName == "boardcast") {
                if (ParamsList[0] == "log") {
                    level.logs.Add(ParamsList[1]);
                }
            }
            else if (ActionName == "game_status") {
                level.gameStarted = ParamsList[0] == "true";
                level.leftTime = float.Parse(ParamsList[1]);
                level.mapWidth = float.Parse(ParamsList[2]);
                level.mapHeight = float.Parse(ParamsList[3]);
                level.autoStart = ParamsList[4] == "true";
                level.autoStartTime = float.Parse(ParamsList[5]);
                level.autoStartMinPlayerCount = int.Parse(ParamsList[6]);
            }
            else if (ActionName == "player_action") {
                string uuid = ParamsList[0];
                if (level.Players.ContainsKey(uuid)) {
                    level.Players[uuid].HandleServerRequest(ParamsList);
                }
            }
            else if (ActionName == "projectile_action") {
                string uuid = ParamsList[0];
                if (level.Projectiles.ContainsKey(uuid)) {
                    level.Projectiles[uuid].HandleServerRequest(ParamsList);
                }
            }
            else if (ActionName == "youkai_action") {
                string uuid = ParamsList[0];
                if (level.Youkais.ContainsKey(uuid)) {
                    level.Youkais[uuid].HandleServerRequest(ParamsList);
                }
            }
            else if (ActionName == "item_action") {
                string uuid = ParamsList[0];
                if (level.Items.ContainsKey(uuid)) {
                    level.Items[uuid].HandleServerRequest(ParamsList);
                }
            }
            else if (ActionName == "create_player") {
                string uuid = ParamsList[0];
                if (!level.Players.ContainsKey(uuid)) {
                    Player playerTarget = new Player(ParamsList[1],
                        new Vector2(float.Parse(ParamsList[2]), float.Parse(ParamsList[3])), uuid, level);
                    level.Players.Add(playerTarget.uuid, playerTarget);
                }
                else {
                    level.Players[uuid].pos = new Vector2(float.Parse(ParamsList[2]), float.Parse(ParamsList[3]));
                }
            }
            else if (ActionName == "create_bullet") {
                string uuid = ParamsList[0];
                if (!level.Projectiles.ContainsKey(uuid)) {
                    Projectile projectileTarget = new Projectile(uuid, ParamsList[1],
                        new Vector2(float.Parse(ParamsList[2]), float.Parse(ParamsList[3])),
                        new Vector2(float.Parse(ParamsList[4]), float.Parse(ParamsList[5])), ParamsList[6], level);
                    level.Projectiles.Add(projectileTarget.uuid, projectileTarget);
                }
                else {
                    level.Projectiles[uuid].bulletType = ParamsList[1];
                    level.Projectiles[uuid].pos = new Vector2(float.Parse(ParamsList[2]), float.Parse(ParamsList[3]));
                    level.Projectiles[uuid].velocity = new Vector2(float.Parse(ParamsList[4]), float.Parse(ParamsList[5]));
                    level.Projectiles[uuid].ownerUuid = ParamsList[6];
                }
            }
            else if (ActionName == "create_youkai") {
                string uuid = ParamsList[0];
                if (!level.Youkais.ContainsKey(uuid)) {
                    Youkai youkaiTarget = new Youkai(uuid, ParamsList[1],
                        new Vector2(float.Parse(ParamsList[2]), float.Parse(ParamsList[3])),
                        new Vector2(float.Parse(ParamsList[4]), float.Parse(ParamsList[5])),
                        float.Parse(ParamsList[6]), level);
                    level.Youkais.Add(youkaiTarget.uuid, youkaiTarget);
                }
                else {
                    level.Youkais[uuid].pos = new Vector2(float.Parse(ParamsList[2]), float.Parse(ParamsList[3]));
                    level.Youkais[uuid].velocity = new Vector2(float.Parse(ParamsList[4]), float.Parse(ParamsList[5]));
                    level.Youkais[uuid].friction = float.Parse(ParamsList[6]);
                }
            }
            else if (ActionName == "create_item") {
                string uuid = ParamsList[0];
                if (!level.Items.ContainsKey(uuid)) {
                    Item item = new Item(uuid, new Vector2(float.Parse(ParamsList[1]), float.Parse(ParamsList[2])),
                        new Vector2(float.Parse(ParamsList[3]), float.Parse(ParamsList[4])));
                    level.Items.Add(uuid, item);
                }
                else {
                    level.Items[uuid].pos = new Vector2(float.Parse(ParamsList[1]), float.Parse(ParamsList[2]));
                    level.Items[uuid].velocity = new Vector2(float.Parse(ParamsList[3]), float.Parse(ParamsList[4]));
                }
            }
            else if (ActionName == "del_player") {
                string uuid = ParamsList[0];
                if (level.Players.ContainsKey(uuid)) {
                    level.Players.Remove(uuid);
                }
            }
            else if (ActionName == "del_bullet") {
                string uuid = ParamsList[0];
                if (level.Projectiles.ContainsKey(uuid)) {
                    level.Projectiles.Remove(uuid);
                }
            }
            else if (ActionName == "del_youkai") {
                string uuid = ParamsList[0];
                if (level.Youkais.ContainsKey(uuid)) {
                    level.Youkais.Remove(uuid);
                }
            }
            else if (ActionName == "del_item") {
                string uuid = ParamsList[0];
                if (level.Items.ContainsKey(uuid)) {
                    level.Items.Remove(uuid);
                }
            }
            else if (ActionName == "particle_burst") {
                string uuid = ParamsList[0];
                if (level.Players.ContainsKey(uuid)) {
                    level.Players[uuid].HandleBurstRequest(ParamsList);
                }
                else if (level.Youkais.ContainsKey(uuid)) {
                    level.Youkais[uuid].HandleBurstRequest(ParamsList);
                }
            }
            else {
                throw new Exception("Invalid Request Received : " + ActionName + " -> " + ParamsList.ToString());
            }
        }
        catch {
            Console.WriteLine("Error Request -> " + ActionName);
            foreach (string actionParam in ParamsList) {
                Console.Write(actionParam + ", ");
            }
            Console.WriteLine();
        }
    }

}